package com.oauth2.service;

import java.util.Date;
import java.util.UUID;

import javax.annotation.Resource;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;

import com.alibaba.fastjson.JSON;
import com.oauth2.dto.AccessTokenResponse;
import com.oauth2.entity.GatewayUser;
import com.oauth2.entity.OauthAccessToken;
import com.oauth2.repository.GatewayUserRepository;
import com.oauth2.repository.OauthAccessTokenRepository;

@Service
@Transactional
public class OauthService {
	public final static Logger logger = LoggerFactory.getLogger(OauthService.class);
	
	@Autowired
    private GatewayUserRepository gatewayUserRepository;
	@Resource
	OauthAccessTokenRepository oauthAccessTokenRepository;
	
	@Resource
	RedisService redisService;

	/**
	 * 客户端授权模式
	 * @param clientId
	 * @param clientSecret
	 * @return
	 */
	public AccessTokenResponse clientCredentials(String clientId,String clientSecret){
		AccessTokenResponse response=new AccessTokenResponse();
		String access_token="";
		GatewayUser entity=gatewayUserRepository.findByid(clientId);
		long expire=entity.getAccessTokenValidity();
		if(entity==null||!clientSecret.equals(entity.getClientSecret())){
			logger.error("invalid_client");
			return null;
		}
		
		//获取未过期的token
		String tokenkey = "access_token:clientId:"+clientId;
		access_token=redisService.get(tokenkey);
		expire=redisService.getExpire(tokenkey);
		if(StringUtils.isEmpty(access_token)){
			//token过期，则重新创建token
			access_token=UUID.randomUUID().toString().replaceAll("-", "");
			redisService.set(GatewayUser.class.getSimpleName()+":token:"+access_token, JSON.toJSONString(entity));
			redisService.set(tokenkey, access_token);
			
			if(entity.getAccessTokenValidity()!=null){
				redisService.expire(GatewayUser.class.getSimpleName()+":token:"+access_token, entity.getAccessTokenValidity());
				redisService.expire(tokenkey, entity.getAccessTokenValidity());
			}else{
				redisService.expire(GatewayUser.class.getSimpleName()+":token:"+access_token, 1800);
				redisService.expire(tokenkey, 1800);
			}
			
		}
		logger.info("access_token:"+access_token);
		response.setAccess_token(access_token);
		response.setExpires_in(expire);
		response.setToken_type("bearer");
		return response;
	}
	
	/**
	 * 用户名密码授权模式
	 * @param username
	 * @param password
	 * @param clientId
	 * @param clientSecret
	 * @return
	 */
	public AccessTokenResponse passwordGrant(String username,String password,String clientId,String clientSecret){
		AccessTokenResponse response=new AccessTokenResponse();
		String access_token="";
		String refresh_token="";
		GatewayUser entity=gatewayUserRepository.findByid(clientId);
		if(entity==null||!clientSecret.equals(entity.getClientSecret())){
			logger.error("invalid_client");
			return null;
		}
		OauthAccessToken oauthAccessToken=oauthAccessTokenRepository.findByClientAndUsername(clientId, username);
		if(oauthAccessToken!=null){
			refresh_token=oauthAccessToken.getRefreshToken();
		}
		access_token=redisService.get("access_token:username+clientId:"+username+clientId);
		//如果token过期，则重新分配access_token和refresh_token
		if(StringUtils.isEmpty(access_token)){
			access_token=UUID.randomUUID().toString().replaceAll("-", "");
			redisService.set(GatewayUser.class.getSimpleName()+":token:"+access_token, JSON.toJSONString(entity));
			redisService.set("access_token:username+clientId:"+username+clientId, access_token);
			
			if(entity.getAccessTokenValidity()!=null){
				redisService.expire(GatewayUser.class.getSimpleName()+":token:"+access_token, entity.getAccessTokenValidity());
				redisService.expire("access_token:username+clientId:"+username+clientId, entity.getAccessTokenValidity());
			}else{
				redisService.expire(GatewayUser.class.getSimpleName()+":token:"+access_token, 1800);
				redisService.expire("access_token:username+clientId:"+username+clientId, 1800);
			}
			
			
			refresh_token=UUID.randomUUID().toString().replaceAll("-", "");
			if(oauthAccessToken==null){
				oauthAccessToken=new OauthAccessToken();
				oauthAccessToken.setClientId(clientId);
				oauthAccessToken.setCreateTime(new Date());
				oauthAccessToken.setRefreshToken(refresh_token);
				oauthAccessToken.setUserName(username);
				oauthAccessTokenRepository.save(oauthAccessToken);
			}else{
				oauthAccessTokenRepository.updateRefreshToken(clientId, username, new Date(), refresh_token);
			}
		}
		logger.info("access_token:"+access_token);
		response.setAccess_token(access_token);
		response.setExpires_in(entity.getAccessTokenValidity());
		response.setToken_type("bearer");
		response.setRefresh_token(refresh_token);
		return response;
	}
	
	/**
	 * refreshtoken授权模式
	 * @param clientId
	 * @param clientSecret
	 * @param refreshToken
	 * @return
	 */
	public AccessTokenResponse refreshToken(String clientId,String clientSecret,String refreshToken){
		AccessTokenResponse response=new AccessTokenResponse();
		String access_token="";
		GatewayUser entity=gatewayUserRepository.findByid(clientId);
		if(entity==null||!clientSecret.equals(entity.getClientSecret())){
			logger.error("invalid_client");
			return null;
		}
		OauthAccessToken oauthAccessToken=oauthAccessTokenRepository.findByRefreshToken(refreshToken);
		if(oauthAccessToken==null){
			logger.error("invalid_refreshtoken");
			return null;
		}
		access_token=UUID.randomUUID().toString().replaceAll("-", "");
		redisService.set(GatewayUser.class.getSimpleName()+":token:"+access_token, JSON.toJSONString(entity));
		redisService.set("access_token:username+clientId:"+oauthAccessToken.getUserName()+oauthAccessToken.getClientId(), access_token);
		
		if(entity.getAccessTokenValidity()!=null){
			redisService.expire(GatewayUser.class.getSimpleName()+":token:"+access_token, entity.getAccessTokenValidity());
			redisService.expire("access_token:username+clientId:"+oauthAccessToken.getUserName()+oauthAccessToken.getClientId(), entity.getAccessTokenValidity());
		}else{
			redisService.expire(GatewayUser.class.getSimpleName()+":token:"+access_token, 1800);
			redisService.expire("access_token:username+clientId:"+oauthAccessToken.getUserName()+oauthAccessToken.getClientId(), 1800);
		}
		
		logger.info("access_token:"+access_token);
		response.setAccess_token(access_token);
		response.setExpires_in(entity.getAccessTokenValidity());
		response.setToken_type("bearer");
		return response;
	}
	
	
	
	
	public GatewayUser validataToken(String access_token){
		String key=GatewayUser.class.getSimpleName()+":token:"+access_token;
		if("".equals(redisService.get(key))||redisService.get(key)==null){
			return null;
		}
		GatewayUser entity=JSON.parseObject(redisService.get(key), GatewayUser.class);
		return entity;
	}
	
	
}
